﻿using System;
using System.ComponentModel;
using System.Net;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace Chess.Common
{
    public class ClientService
    {
        private TcpClient _tcpClient;
        private string _userName;
        private string _password;

        public ClientService(string userName, string password)
        {
            _userName = userName;
            _password = password;
        }

        public void Connect(IPAddress address, int port)
        {
            _tcpClient = new TcpClient();
            _tcpClient.Connect(address, port);
        }

        public async Task<RegistrationAnswerPackage> Register()
        {
            var passwordHash = GetHash(_password);
            var registerPackage = new RegistrationRequestPackage(_userName, passwordHash);
            await SendPackageAsync(registerPackage);
            //var eventArgs = new SocketAsyncEventArgs();

            //var stream = _tcpClient.GetStream();
            //byte[] buffer = new byte[1024];
            //await stream.ReadAsync(buffer, 0, 1024);
            //var p = PackageSerializer.Deserialize(buffer);
            //var answerPackage = p as RegistrationAnswerPackage;
            var answerPackage = await ReceivePackageAsync() as RegistrationAnswerPackage;

            return answerPackage;
            //if (_tcpClient.Client.ReceiveAsync(eventArgs))
            //{

            //    var data = eventArgs.Buffer;
            //    Package p = PackageSerializer.Deserialize(data);
            //}
        }

        public async Task<LoginAnswerPackage> Login()
        {
            var passwordHash = GetHash(_password);
            var loginPackage = new LoginRequestPackage(_userName, passwordHash);
            await SendPackageAsync(loginPackage);
            var loginPackageAnswer = await ReceivePackageAsync() as LoginAnswerPackage;

            return loginPackageAnswer;
        }

        public async void Exit()
        {
            var exitPackage = new ExitPackage(_userName);
            await SendPackageAsync(exitPackage);
        }

        public Task SendPackageAsync(Package package)
        {
            var buffer = PackageSerializer.Serialize(package);
            //using (var ns = _tcpClient.GetStream())
            var ns = _tcpClient.GetStream();
            {
                return ns.WriteAsync(buffer, 0, buffer.Length);
                //ns.Write(buffer, 0, buffer.Length); // TODO: write async
            }
        }

        public async Task<Package> ReceivePackageAsync()
        {
            Func<Package> callback = () =>
            {
                var stream = _tcpClient.GetStream();
                byte[] buffer = new byte[1024];
                Task r = stream.ReadAsync(buffer, 0, 1024);
                TaskAwaiter awaiter = r.GetAwaiter();
                awaiter.GetResult();
                //r.Wait();
                
                var package = PackageSerializer.Deserialize(buffer);
                return package;
            };

            return await Task.Run(callback);
        }

        private string GetHash(string password)
        {
            SHA1 sha = new SHA1CryptoServiceProvider();
            var bytes = sha.ComputeHash(Encoding.UTF8.GetBytes(password));
            string hash = Encoding.UTF8.GetString(bytes);
            return hash;
        }
    }
}
